home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Games Collection 1
/
software vault.zip
/
software vault
/
CDR10
/
ROOMMAZE.ZIP
/
ROOMMAZE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-18
|
14KB
|
424 lines
/****************************************/
/* ROOMMAZE.C */
/* (C) Copyright 1993 David Bollinger */
/* send comments to CIS ID# 72510,3623 */
/* compiled with Borland C++ 3.0 */
/* command line: bcc -ms -v- roommaze.c */
/****************************************/
#include <bios.h>
#include <stdlib.h>
#include <time.h>
#include "roommaze.h"
#define AND &&
#define OR ||
#define NOT !
#define SCREENX 320 // screen x dimension
#define SCREENY 200 // screen y dimension
#define MAZEX 80 // maze x dimension
#define MAZEY 80 // maze y dimension
#define GRIDX 4 // how coarse are the x coordinates
#define GRIDY 4 // how coarse are the y coordinates
// basically defines minimum width and height
// also helps align room boundaries
// 4 seems to be a pretty good value
#define NUMRECT 32 // how many rectangles to draw rooms with
#define MAXFLOOR 8 // how many different colors of floor (2-15)
// maze objects, defined by the following weighting map:
// +---+
// | 1 |
// +---+---+---+
// | 2 |X,Y| 4 |
// +---+---+---+
// | 8 |
// +---+
//
#define FL 0 // unused, empty floor
#define NE 1 // north end
#define WE 2 // west end
#define LR 3 // lower right
#define EE 4 // east end
#define LL 5 // lower left
#define HO 6 // horizontal wall
#define ST 7 // south T
#define SE 8 // south end
#define VE 9 // vertical wall
#define UR 10 // upper right
#define ET 11 // east T
#define UL 12 // upper left
#define WT 13 // west T
#define NT 14 // north T
#define CC 15 // central cross
#define HD 16 // horizontal door
#define VD 17 // vertical door
#define F1 18 // floor 1
#define F2 19 // floor 2
#define F3 20 // floor 3
#define F4 21 // floor 4
#define F5 22 // floor 5
#define F6 23 // floor 6
#define F7 24 // floor 7
#define F8 25 // floor 8
#define F9 26 // floor 9
#define Fa 27 // floor 10
#define Fb 28 // floor 11
#define Fc 29 // floor 12
#define Fd 30 // floor 13
#define Fe 31 // floor 14
#define Ff 32 // floor 15
/********************/
/* global variables */
/********************/
char maze[MAZEY][MAZEX];
/***********************/
/* function prototypes */
/***********************/
void MakeRooms(void);
void ClarifyWalls(void);
void MakeDoors(void);
void TraceWallForDoorX(int sx, int sy);
void TraceWallForDoorY(int sx, int sy);
void SimplifyMaze(void);
void SetVideoMode(int mode);
void Rectangle(int x1, int y1, int x2, int y2, int c);
void WriteMaze(int x, int y, char c);
char ReadMaze(int x, int y);
void CheckOrder(int *a, int *b);
/***************************************************************************/
main()
{
randomize();
SetVideoMode(19); // 320x200 256 color VGA graphics mode
while(bioskey(1)) // chew up any keys waiting in buffer
bioskey(0);
// insert extra bioskey(0)'s to see each step
MakeRooms(); // make some walled in rooms with rectangles
ClarifyWalls(); // calculate exact wall type for each wall
MakeDoors(); // find walls and insert doors
// save array to file here (?)
SimplifyMaze(); // make it look nice on VGA
bioskey(0); // wait for a key
SetVideoMode(3); // return to 80x25 text mode
return 0;
}
/***************************************************************************/
/* MakeRooms creates a number of random outlined rectangles. As */
/* MAXFLOOR is increased it is more likely that the current room */
/* color will not match any underlying room colors, thus there */
/* will be more isolated "island" rooms of simpler shape. As */
/* MAXFLOOR is decreased the opposite is true, resulting in fewer */
/* distinct rooms but each room being more complex in shape. */
/* Note that while MAXFLOOR=1 will accomplish nothing, other */
/* small values (including 2) can still generate interesting mazes */
/*******************************************************************/
void MakeRooms(void)
{
int numrects, r, x1, y1, x2, y2, c;
numrects = NUMRECT;
/*****************************************************/
/* first, create a "base" floor over the entire maze */
/*****************************************************/
Rectangle(0,0,MAZEX-1,MAZEY-1, F1);
for (r=numrects; r>0; r--)
{
x1 = random((int)(MAZEX/GRIDX)) * GRIDX;
y1 = random((int)(MAZEY/GRIDY)) * GRIDY;
x2 = x1 + random((int)(MAZEX/GRIDX)) * GRIDX;
y2 = y1 + random((int)(MAZEY/GRIDY)) * GRIDY;
if (x2 > MAZEX-1)
x2 = MAZEX-1;
if (y2 > MAZEY-1)
y2 = MAZEY-1;
c = random(MAXFLOOR)+F1;
Rectangle(x1, y1, x2, y2, c);
}
}
/***************************************************************************/
/* ClarifyWalls identifies the exact wall type of each WALL object */
/* by examining its neighbors. See weighting map above for an */
/* explanation of the calculation of index. */
/*******************************************************************/
void ClarifyWalls(void)
{
register int x, y, index;
for (y=0; y<MAZEY; y++)
for (x=0; x<MAZEX; x++)
{
/*********************************/
/* if this is floor then skip it */
/*********************************/
if (ReadMaze(x,y) >= F1 )
continue;
/**********************************************************/
/* check if neighboring squares are numerically less than */
/* floor type 1, indicating some type of wall, if a wall */
/* then it affects the index value based on its location */
/**********************************************************/
index = (ReadMaze(x, y-1) < F1) ? 1 : 0;
index += (ReadMaze(x-1, y) < F1) ? 2 : 0;
index += (ReadMaze(x+1, y) < F1) ? 4 : 0;
index += (ReadMaze(x, y+1) < F1) ? 8 : 0;
WriteMaze(x, y, index);
}
}
/***************************************************************************/
/* MakeDoors scans for vertical and horizontal walls and inserts */
/* a door at a random position along the length or width of the wall. */
/* This method generally creates more doors than necessary (certainly */
/* more than a human would place for the same map), but it does */
/* guarantee that all areas of the maze are accessable. Alternatively, */
/* a flood-fill type recursive method could scan the rooms for bordering */
/* rooms and only insert a single door for each unique neighboring room, */
/* but I wanted to stay away from recursion for speed reasons */
/*************************************************************************/
void MakeDoors(void)
{
register int x, y, here;
for (y=1; y<MAZEY-1; y++)
for (x=1; x<MAZEX-1; x++)
{
here = ReadMaze(x, y);
if (here == HO) // found a horizontal wall
TraceWallForDoorX(x, y); // try to make a horizontal door
if (here == VE) // found a vertical wall
TraceWallForDoorY(x, y); // try to make a vertical door
}
}
/***************************************************************************/
/* TraceWallForDoorX scans horizontally trying to identify a wall segment */
/* if it finds one, it inserts a door randomly along its length */
/**************************************************************************/
void TraceWallForDoorX(int sx, int sy)
{
register int inc, x1, x2;
char here;
// scan to the left
inc = 1;
while(sx-inc > 0)
{
here = ReadMaze(sx-inc, sy);
if (here==HD) // there is already a door on this wall
return;
if (here != HO) // came to the end of the wall
break;
inc++;
}
x1 = sx-inc+1;
// scan to the right
inc = 1;
while (sx+inc < MAZEX-1)
{
here = ReadMaze(sx+inc, sy);
if (here==HD) // there is already a door on this wall
return;
if (here != HO) // came to the end of the wall
break;
inc++;
}
x2 = sx+inc-1;
if (x2-x1 > 1)
WriteMaze(random(x2-x1)+x1, sy, HD);
}
/***************************************************************************/
/* TraceWallForDoorY scans vertically trying to identify a wall segment */
/* if it finds one, it inserts a door randomly along its length */
/************************************************************************/
void TraceWallForDoorY(int sx, int sy)
{
register int inc, y1, y2;
char here;
// scan above
inc = 1;
while(sy-inc > 0)
{
here = ReadMaze(sx, sy-inc);
if (here==VD) // there is already a door on this wall
return;
if (here != VE) // came to the end of the wall
break;
inc++;
}
y1 = sy-inc+1;
// scan below
inc = 1;
while (sy+inc < MAZEY-1)
{
here = ReadMaze(sx, sy+inc);
if (here==VD) // there is already a door on this wall
return;
if (here != VE) // came to the end of the wall
break;
inc++;
}
y2 = sy+inc-1;
if (y2-y1 > 1)
WriteMaze(sx, random(y2-y1)+y1, VD);
}
/***************************************************************************/
/* SimplifyMaze un-translates all of the various floor, wall and door */
/* objects into 3 simple floor, wall and door objects. Makes it look */
/* nicer with this simple VGA display, but it may be better to leave it */
/* complex for actual use in a game */
/************************************************************************/
void SimplifyMaze(void)
{
register int x, y;
for (y=0; y<MAZEY; y++)
for (x=0; x<MAZEX; x++)
switch(ReadMaze(x, y))
{
case FL : break;
case F1 :
case F2 :
case F3 :
case F4 :
case F5 :
case F6 :
case F7 :
case F8 :
case F9 :
case Fa :
case Fb :
case Fc :
case Fd :
case Fe :
case Ff : WriteMaze(x, y, FL); break;
case HD : break;
case VD : WriteMaze(x, y, HD); break;
case CC : break;
default : WriteMaze(x, y, CC); break;
}
}
/***************************************************************************/
/* BIOS call to set video mode */
/*******************************/
void SetVideoMode(int mode)
{
asm xor ah, ah
asm mov al, byte ptr mode
asm int 10h
}
/***************************************************************************/
void Rectangle(int x1, int y1, int x2, int y2, int c)
{
int x, y;
/********************************************/
/* verify that x2>=x1 and y2>=y1 */
/* not really needed as the code sits, but */
/* best to be safe in case code is modified */
/********************************************/
CheckOrder(&x1, &x2);
CheckOrder(&y1, &y2);
/*******************************************************/
/* draw interior of rectangle with desired floor color */
/*******************************************************/
for (y=y1+1; y<y2; y++)
for (x=x1+1; x<x2; x++)
WriteMaze(x, y, c);
/*********************************************************/
/* now draw smart border - only draw border if existing */
/* color is not the same as requested floor color - this */
/* allows the rectangles to overlap and create more */
/* interesting shapes than simple rectangles */
/*********************************************************/
for (x=x1; x<=x2; x++)
{
if (ReadMaze(x, y1) != c)
WriteMaze(x, y1, CC);
if (ReadMaze(x, y2) != c)
WriteMaze(x, y2, CC);
}
for (y=y1; y<=y2; y++)
{
if (ReadMaze(x1, y) != c)
WriteMaze(x1, y, CC);
if (ReadMaze(x2, y) != c)
WriteMaze(x2, y, CC);
}
}
/***************************************************************************/
void WriteMaze(int x, int y, char c)
{
if ((x>=0) AND (x<MAZEX) AND (y>=0) AND (y<MAZEY))
{
maze[y][x] = c;
// optional putpixel routine for graphic output
asm mov ax, 0xa000
asm mov es, ax
asm mov bx, word ptr y
asm shl bx, 1
asm mov bx, word ptr ytable[bx]
asm add bx, word ptr x
asm mov ax, word ptr c
asm mov byte ptr es:[bx], al
}
// could return an error if needed
}
/***************************************************************************/
char ReadMaze(int x, int y)
{
if ((x>=0) AND (x<MAZEX) AND (y>=0) AND (y<MAZEY))
return maze[y][x];
else
return F1; // return floor if out of range
// so that ClarifyWalls works properly
}
/***************************************************************************/
void CheckOrder(int *a, int *b)
{
int temp;
if (*a > *b)
{
temp = *a;
*a = *b;
*b = temp;
}
}
/***************************************************************************/
/* end of roommaze.c */